package com.sne.airways.system.service.impl;

import com.sne.airways.basecore.exceptions.AppException;
import com.sne.airways.basecore.service.impl.BaseServiceImpl;
import com.sne.airways.system.annotation.MethodLog;
import com.sne.airways.system.constants.StatusType;
import com.sne.airways.system.dao.OperationDAO;
import com.sne.airways.system.dto.TdOperationCheckDTO;
import com.sne.airways.system.dto.TdOperationDTO;
import com.sne.airways.system.enums.ModuleEnum;
import com.sne.airways.system.enums.OpTypeEnum;
import com.sne.airways.system.pojo.TdOperation;
import com.sne.airways.system.pojo.TdRoleOperation;
import com.sne.airways.system.service.OperationService;
import com.sne.airways.system.utils.AppUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: skyline
 * Date: 12-2-13
 * Time: 下午3:19
 * To change this template use File | Settings | File Templates.
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class OperationServiceImpl extends BaseServiceImpl implements OperationService {
    @Autowired
    private OperationDAO operationDAO;
    /**
     * 返回需要选中的菜单列表
     * @param operationId
     * @param status
     * @return
     * @throws AppException
     *
     */
    public Set<TdOperationDTO> queryPrivateOperationTree(String operationId, String status) throws AppException {
        if (AppUtils.isAdministrator()){
            //是系统管理员 则不过滤系统权限
            Set<TdOperation> operationSet = operationDAO.queryChildTree(operationId, status);
            Set<TdOperationDTO> children =  childTreeDTO(operationSet);
            return children;
        }else{
            //不是系统管理员 过滤系统权限
            Set<TdOperation> operationSet = operationDAO.queryPrivateChildTree(AppUtils.getCurrentUser().getUserNo(), operationId, status);
            Set<TdOperationDTO> children =  privateChildTreeDTO(operationSet);
            return children;
        }
    }

    /**
     * 根据菜单Id和状态返回菜单列表
     *
     * @param operationId
     * @param status
     * @return
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    public Set<TdOperationDTO> queryOperationTree(String operationId, String status) throws AppException {
        Set<TdOperation> operationSet = operationDAO.queryChildTree(operationId, status);
        Set<TdOperationDTO> children =  queryOperationTreeDTO(operationSet);
        return children;
    }

    /**
     * 保存菜单
     *
     * @param operationId
     * @param parentId
     * @param menuName
     * @param menuView
     * @param menuController
     * @param menuIndex
     * @param menuLevel
     * @param version
     * @param status
     * @param iconCls
     * @param expandedCls
     * @param collapsedCls
     * @return
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    @MethodLog(opType = OpTypeEnum.添加菜单,module = ModuleEnum.菜单管理)
    public TdOperationDTO saveOperation(String operationId, String parentId, String menuName, String menuView, String menuController, int menuIndex, int menuLevel, int version, String status, String iconCls, String expandedCls, String collapsedCls) throws AppException {
        int count = operationDAO.queryOperationIsRepeat(null,menuName,null);
        if(count > 0) throw new AppException("菜单["+menuName+"]已经存在!");
        TdOperation base = loadObject(TdOperation.class,parentId);
        TdOperation tdOperation = new TdOperation();
        tdOperation.setParent(base);
        tdOperation.setMenuName(menuName);
        tdOperation.setMenuView(menuView);
        tdOperation.setMenuController(menuController);
        tdOperation.setMenuIndex(menuIndex);
        tdOperation.setMenuLevel(menuLevel);
        tdOperation.setExpandedCls(expandedCls);
        tdOperation.setCollapsedCls(collapsedCls);
        tdOperation.setIconCls(iconCls);
        tdOperation.setVersion(version);
        tdOperation.setStatus(status);
        tdOperation.setCreateDate(new Date());
        tdOperation.setCreateUser(AppUtils.getCurrentUser());
        saveObject(tdOperation);
        TdOperationDTO dto   = new TdOperationDTO();
        String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
        BeanUtils.copyProperties(tdOperation, dto, ignoreProperties);
        //设置创建人
        dto.setCreateUser(tdOperation.getCreateUser() ==null?null:tdOperation.getCreateUser().getUserName());
        //设置修改人
        dto.setModifyUser(tdOperation.getModifyUser() ==null?null:tdOperation.getModifyUser().getUserName());
        //设置父级ID
        dto.setParentId(tdOperation.getParent().getOperationId());
        //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
        Set<TdOperation> dynamicChildren = tdOperation.getChildren();
        if(!dynamicChildren.isEmpty()){
            dto.setLeaf(false);
        }else{
            dto.setLeaf(true);
        }
        return dto;
    }

    /**
     * 更新菜单
     *
     * @param operationId
     * @param parentId
     * @param menuName
     * @param menuView
     * @param menuController
     * @param menuIndex
     * @param menuLevel
     * @param version
     * @param status
     * @param iconCls
     * @param expendedCls
     * @param collapsedCls
     * @return
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    @MethodLog(opType = OpTypeEnum.编辑菜单,module = ModuleEnum.菜单管理)
    public TdOperationDTO updateOperation(String operationId, String parentId, String menuName, String menuView, String menuController, int menuIndex, int menuLevel, int version, String status, String iconCls, String expendedCls, String collapsedCls) throws AppException {
        int count = operationDAO.queryOperationIsRepeat(operationId,menuName,null);
        if(count > 0) throw new AppException("菜单["+menuName+"]已经存在!");
        TdOperation tdOperation = loadObject(TdOperation.class,operationId);
        isCurrentVersion(tdOperation,version);
        tdOperation.setMenuName(menuName);
        tdOperation.setMenuView(menuView);
        tdOperation.setMenuController(menuController);
        tdOperation.setMenuIndex(menuIndex);
        tdOperation.setMenuLevel(menuLevel);
        tdOperation.setExpandedCls(expendedCls);
        tdOperation.setCollapsedCls(collapsedCls);
        tdOperation.setIconCls(iconCls);
        tdOperation.setVersion(version);
        tdOperation.setStatus(status);
        tdOperation.setModifyDate(new Date());
        tdOperation.setModifyUser(AppUtils.getCurrentUser());
        updateObject(tdOperation);
        TdOperationDTO dto   = new TdOperationDTO();
        String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
        BeanUtils.copyProperties(tdOperation, dto, ignoreProperties);
        //设置创建人
        dto.setCreateUser(tdOperation.getCreateUser() ==null?null:tdOperation.getCreateUser().getUserName());
        //设置修改人
        dto.setModifyUser(tdOperation.getModifyUser() ==null?null:tdOperation.getModifyUser().getUserName());
        //设置父级ID
        dto.setParentId(tdOperation.getParent().getOperationId());
        //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
        Set<TdOperation> dynamicChildren = tdOperation.getChildren();
        if(!dynamicChildren.isEmpty()){
            dto.setLeaf(false);
        }else{
            dto.setLeaf(true);
        }
        return dto;
    }

    /**
     * 删除菜单
     *
     * @param operationId
     * @param version
     * @return
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    @MethodLog(opType = OpTypeEnum.删除菜单,module = ModuleEnum.菜单管理)
    public void deleteOperation(String operationId, int version) throws AppException {
        TdOperation tdOperation = loadObject(TdOperation.class,operationId);
        isCurrentVersion(tdOperation,version);
        tdOperation.setVersion(version);
        deleteObject(tdOperation);
    }

    /**
     * 修改菜单排序
     *
     * @param operationId
     * @param parentId
     * @param oldParentId
     * @param menuIndex
     * @param oldMenuIndex
     * @param menuLevel
     * @param oldMenuLevel
     * @param version
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    @MethodLog(opType = OpTypeEnum.菜单排序,module = ModuleEnum.菜单管理)
    public void changeOperationIndex(String operationId, String parentId, int menuIndex,int menuLevel, String oldParentId,int oldMenuIndex,  int oldMenuLevel, int version) throws AppException {
        if(oldMenuLevel != menuLevel){
            operationDAO.changeBeforeIndex(operationId,parentId,menuIndex,menuLevel,oldParentId,oldMenuIndex,oldMenuLevel,version);
            operationDAO.changeAfterIndex(operationId,parentId,menuIndex,menuLevel,oldParentId,oldMenuIndex,oldMenuLevel,version);
        }else{
            operationDAO.changeCurrentIndex(operationId,parentId,menuIndex,menuLevel,oldParentId,oldMenuIndex,oldMenuLevel,version);
        }
        operationDAO.changeIndex(operationId,parentId,menuIndex,menuLevel,oldParentId,oldMenuIndex,oldMenuLevel,version);
    }

    /**
     * 根据菜单Id和状态返回菜单列表
     *
     * @param operationId
     * @param roleId
     * @param status
     * @return
     * @throws com.sne.airways.basecore.exceptions.AppException
     *
     */
    @Override
    public Set<TdOperationCheckDTO> queryOperationCheckedTree(String operationId,String roleId, String status) throws AppException {
        Set<TdOperation> operationSet = operationDAO.queryChildTree(operationId, status);
        Set<TdOperationCheckDTO> children =  queryOperationTreeCheckDTO(operationSet, roleId);
        return children;
    }

    private Set<TdOperationDTO> childTreeDTO(Set<TdOperation> childTree) throws  AppException {
        Set<TdOperationDTO> finalChildren = new HashSet<TdOperationDTO>();
        for(TdOperation operation:childTree){
            TdOperationDTO   dto   = new TdOperationDTO();
            String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
            BeanUtils.copyProperties(operation, dto, ignoreProperties);
            dto.setParentId(operation.getParent()==null?null:operation.getParent().getOperationId());
            //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
            Set<TdOperation> dynamicChildren = operation.getChildren();
            if(!dynamicChildren.isEmpty()){
                dto.setChildren(childTreeDTO(dynamicChildren));
                dto.setLeaf(false);
            }else{
                dto.setLeaf(true);
            }
            finalChildren.add(dto);
        }
        return finalChildren;
    }
    private Set<TdOperationDTO> queryOperationTreeDTO(Set<TdOperation> childTree) throws  AppException {
        Set<TdOperationDTO> finalChildren = new HashSet<TdOperationDTO>();
        for(TdOperation operation:childTree){
            TdOperationDTO   dto   = new TdOperationDTO();
            String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
            BeanUtils.copyProperties(operation, dto, ignoreProperties);
            dto.setParentId(operation.getParent()==null?null:operation.getParent().getOperationId());
            //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
            Set<TdOperation> dynamicChildren = operation.getChildren();
            if(!dynamicChildren.isEmpty()){
                dto.setChildren(childTreeDTO(dynamicChildren));
                dto.setLeaf(false);
            }else{
                dto.setLeaf(true);
            }
            finalChildren.add(dto);
        }
        return finalChildren;
    }
    private Set<TdOperationCheckDTO> queryOperationTreeCheckDTO(Set<TdOperation> childTree,String roleId) throws  AppException {
        Set<TdOperationCheckDTO> finalChildren = new HashSet<TdOperationCheckDTO>();
        for(TdOperation operation:childTree){
            TdOperationCheckDTO   dto   = new TdOperationCheckDTO();
            String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
            BeanUtils.copyProperties(operation, dto, ignoreProperties);
            dto.setParentId(operation.getParent()==null?null:operation.getParent().getOperationId());
            //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
            Set<TdOperation> dynamicChildren = operation.getChildren();
            if(!dynamicChildren.isEmpty()){
                dto.setChildren(queryOperationTreeCheckDTO(dynamicChildren, roleId));
                dto.setLeaf(false);
            }else{
                dto.setLeaf(true);
            }
            Set<TdRoleOperation> dynamicRoles = operation.getRoles();
            boolean flag = false;
            for(TdRoleOperation role:dynamicRoles){
                if(role.getRole().getRoleId().equals(roleId)){
                    flag = true;
                    break;
                }
            }
            if(flag) dto.setChecked(true); //如果角色列表中包含该角色，然后就设置菜单选中
            finalChildren.add(dto);
        }
        return finalChildren;
    }
    private Set<TdOperationDTO> privateChildTreeDTO(Set<TdOperation> childTree) throws AppException{
        Set<TdOperationDTO> finalChildren = new HashSet<TdOperationDTO>();
        for(TdOperation operation:childTree){
            if(StringUtils.equals(operation.getStatus(),StatusType.冻结.getValue()))
                continue;
            TdOperationDTO   dto   = new TdOperationDTO();
            String[] ignoreProperties = {"parent","children","roles","createUser","modifyUser"};
            BeanUtils.copyProperties(operation,dto,ignoreProperties);
            //下面是最重要的一步 就是递归子菜单，并且返回是否叶子节点
            Set<TdOperation> dynamicChildren = operationDAO.queryPrivateChildTree(AppUtils.getCurrentUser().getUserNo(), operation.getOperationId(), StatusType.启用.getValue());
            if(!dynamicChildren.isEmpty()){
                dto.setChildren(privateChildTreeDTO(dynamicChildren));
                dto.setLeaf(false);
            }else{
                dto.setLeaf(true);
            }
            finalChildren.add(dto);
        }
        return finalChildren;
    }
}
